from flask_docs import ApiDoc
from flask import current_app
import requests
from config import Config, Dic2Ob
from plugin.logger import MyLogger
import functools

logger = MyLogger.logger
docs_config = Config.config_apidoc.apidoc


def get_api_data(self):
    """
    重构flask_docs里面的对应方法，支持重命名树节点
    """
    from flask_docs import logger as apidocs_log, PROJECT_NAME
    data_dict = {}

    blueprints = current_app.config["API_DOC_MEMBER"]
    titles = current_app.config["API_DOC_TITLE"]
    for rule in current_app.url_map.iter_rules():
        # current_app.url_map.iter_rules()是获取当前服务器上所有的路由
        # f = str(rule).split("/")[1]
        f = str(rule)
        f_capitalize = None
        for bp in blueprints:
            if bp.url_prefix and bp.url_prefix in f:
                sort_no = blueprints.index(bp)
                if titles and len(titles) > sort_no:
                    f_capitalize = titles[sort_no]
                else:
                    f_capitalize = bp.url_prefix[1:].replace("/", ".").capitalize()
                break

        if f_capitalize is None:
            continue
        if f_capitalize not in data_dict:
            data_dict[f_capitalize] = {"children": []}

        api = {
            "name": "",
            "name_extra": "",
            "url": "",
            "method": "",
            "doc": "",
            "doc_md": "",
            "router": f_capitalize,
            "api_type": "api",
        }

        try:
            func = current_app.view_functions[rule.endpoint]

            name = self._get_api_name(func)
            req = str(rule)
            url = str(rule)
            method = " ".join([r for r in rule.methods if r in current_app.config["API_DOC_METHODS_LIST"]])
            if method:
                url = "{}\t[{}]".format(url, "\t".join(method.split(" ")))

            result = filter(
                lambda x: x["name"] == name,
                data_dict[f_capitalize]["children"],
            )
            result_list = list(result)
            if len(result_list) > 0:
                result_list[0]["url"] = result_list[0]["url"] + " " + url
                result_list[0]["url"] = " ".join(list(set(result_list[0]["url"].split(" "))))
                result_list[0]["method"] = result_list[0]["method"] + \
                    " " + method
                result_list[0]["method"] = " ".join(list(set(result_list[0]["method"].split(" "))))
                raise RuntimeError

            api["url"] = url
            api["method"] = method

            doc = self._get_api_doc(func)

            (
                api["doc"],
                api["name_extra"],
                api["doc_md"],
            ) = self._get_doc_name_extra_doc_md(doc)

            if api["name_extra"] == '':
                api["name"] = name
            else:
                api["name"] = api["name_extra"]
                api["name_extra"] = name

            # 自动生成resp文档内容
            # if docs_config and '__resp_example__' in api["doc_md"]:
            #     host = docs_config.localhost or docs_config.publichost
            #     url = "{}/{}".format(host.strip('/'), req.strip('/'))
            #     # start = api["doc_md"].index(publichost)
            #     # end = api["doc_md"].index('```', start)
            #     # url = api["doc_md"][start:end].replace(publichost, docs_config.localhost).strip()
            #     try:
            #         # if not url.endswith('-') and not url.endswith('-\n'):  # 使用-结尾的不做请求
            #         if not api["doc_md"].contains('```cmd\n      -\n    ```'):
            #             resp = requests.request(method, url)
            #             api["doc_md"] = api["doc_md"].replace('__resp_example__', resp.text)
            #     except Exception:
            #         logger.error('使用req样例请求失败，请检测apidoc.host配置以及req样例是否正确，{}'.format(url))

        except Exception as e:
            apidocs_log.exception("{} error - {}".format(PROJECT_NAME, e))
        else:
            data_dict[f_capitalize]["children"].append(api)

        if data_dict[f_capitalize]["children"] == []:
            data_dict.pop(f_capitalize)
        else:
            data_dict[f_capitalize]["children"].sort(key=lambda x: x["name"])

    return data_dict


# @staticmethod
def Create_Doc(funcname: str = None):
    """
    该注解作用是将api文档补充得更加完整，不使用也不影响文档的生成。api文档是按照对应接口方法的注释生成的，这个方法是读取config.yml里面的配置加到注释里面去。
        @name: <default fun.__name__> 和配置文件中apidoc.method.[name]匹配，读取对应的配置作为注释
    """

    def decorator(func):
        nonlocal funcname
        try:
            assert docs_config, 'apidoc配置文件缺少apidoc项'
            funcname = funcname or func.__name__.lower()
            docs_config.content = docs_config.content or content
            func_config = Dic2Ob(docs_config.method[funcname] if docs_config.method.__contains__(funcname) else {
                'descr': '-',
                'args': '-|-|-|-',
                'req': '-',
                'respargs': '-',
                'resp': ''
            })  # 对应的方法的配置
            apidesc = func_config.descr  # 接口描述
            args = func_config.args or "-|-|-|-"  # 接口参数
            respargs = func_config.respdescr  # 返回字段描述
            extradescr = docs_config.extradescr or ""  # 额外描述
            doc = docs_config.content.format(apidesc, args, respargs, extradescr)
            func.__doc__ = func.__doc__ + doc if func.__doc__ else doc
        except AssertionError as e:
            logger.error(e)

        @functools.wraps(func)
        def decorated_function(*args, **kw):
            return func(*args, **kw)

        return decorated_function

    return decorator


ApiDoc._get_api_data = get_api_data

content = """
    @@@
    ### 接口描述
    {0}

    ### 可传参数
    | 参数名 | 是否必传 | 数据类型 | 参数说明 |
    |--|--|--|--|
    {1}

    ### 返回字段
    | 字段 | 说明 | 数据类型 |
    |--|--|--|
    {2}

    {3}
    @@@
"""

# content = """
#     @@@
#     ### 接口描述
#     {0}

#     ### 可传参数
#     | 参数名 | 是否必传 | 数据类型 | 参数说明 |
#     |--|--|--|--|
#     {1}

#     ### 请求样例
#     ```cmd
#       {2}
#     ```

#     ### 返回字段
#     | 字段 | 说明 | 数据类型 |
#     |--|--|--|
#     {3}

#     ### 返回样例
#     ```json
#       {4}
#     ```

#     {5}
#     @@@
# """

if not docs_config.__contains__(content):
    """ 默认以本文件的content作为生成的在线文档的模板，如果配置文件里面有配置apidoc.content，那就以配置文档优先 """
    docs_config['content'] = content
    docs_config = Dic2Ob(docs_config)
